package worldobjects;

import java.awt.Color;

import raytracing.Ray;
import raytracing.RaycastResult;
import structs.Matrix;
import structs.Vector3;

public class TriangleMesh implements IWorldObject{

	public Matrix worldMatrix = Matrix.identity();
	
	public Vector3[] oriVerts; //positions in own coordinate system
	public Vector3[] oriNormals;
	
	public Vector3[] verts; //translatepositions
	public Vector3[] normals;
	public int[][] triangles;
	public boolean reflective;
	public boolean castsShadow = true;
	public float selfIllumination = 1;
	/* SELF ILLUMINATION NOTE:
	 * range [0..infinity], will be multiplied with the final calculated color
	 * 0 means this object will appear black.
	 * 1 means this objects has no 'self illumination'
	 */
	
	public Color diffuseColor; //only set when not using diffusemaps!!
	
	public TriangleMesh(int nbVerts, int nbTris)
	{
		verts = new Vector3[nbVerts];
		normals = new Vector3[nbVerts];
		oriVerts = new Vector3[nbVerts];
		oriNormals = new Vector3[nbVerts];
		
		triangles = new int[nbTris][3];		
	}
	
	public void setWorldMatrix(Matrix m)
	{
		worldMatrix = m;
		for(int i=0; i<oriVerts.length; i++)
		{
			verts[i] = m.multiply(oriVerts[i]);
		}
				
		Matrix normalMatrix = m.getInverseTimesDet().getTranspose();
		for(int i=0; i<oriNormals.length; i++)
		{
			normals[i] = normalMatrix.multiply(oriNormals[i]);
		}
	}

	@Override
	public boolean isHit(Ray ray, float minDist, float maxDist, RaycastResult result) {				
		result.distance = Integer.MAX_VALUE;
		
		for(int i=0; i<triangles.length; i++)
		{			
			Triangle triangle = new Triangle(verts[triangles[i][0]-1], verts[triangles[i][1]-1], verts[triangles[i][2]-1]);
			triangle.n1 = normals[triangles[i][0]-1];
			triangle.n2 = normals[triangles[i][1]-1];
			triangle.n3 = normals[triangles[i][2]-1];
			RaycastResult tempRes = new RaycastResult();
						
			if(triangle.isHit(ray, minDist, maxDist, tempRes))
			{				
				if(tempRes.distance > 0 && tempRes.distance < result.distance)
				{
					result.distance = tempRes.distance;
					result.ray = tempRes.ray;
					result.diffuseColor = tempRes.diffuseColor;
					result.normal = tempRes.normal;
					result.specularColor = tempRes.specularColor;
					result.specularIntensity = tempRes.specularIntensity;
					result.reflective = reflective;
				}					
			}			
		}
		
		if(diffuseColor != null)
			result.diffuseColor = diffuseColor;
		
		result.selfllumination = selfIllumination;
		
		return result.distance != Integer.MAX_VALUE;		
	}

	@Override
	public BoundingBox getBoundingBox() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean castsShadow() {
		return castsShadow;
	}

}
